"""
# Author : YuuSoo
# version : python 3.8
# Time : 2023/1/7 11:40
"""
# 程序所用扩展包
import geatpy as ea
import requests
import yaml
import pickle
from sklearn.ensemble import RandomForestRegressor
import numpy as np
import pandas as pd
import warnings

warnings.filterwarnings('ignore', message='X does not have valid feature names')
# ==================================================================

# ==================================================================
# import ......
import logging
import flask_restful
# 自定义模块
from errors import my_abort, generate_response, ResponseCode

# 自定义错误
flask_restful.abort = my_abort
root_logger = logging.getLogger('root')
logger = logging.getLogger('main')


# ==================================================================


# ==================================================================
import os
import csv
from flask import current_app

import os
import csv

import os
import csv


import os
import csv

def function(Authorization, id):
    datas = {}

    try:
        value_qs = function_qs(Authorization, id)
        if value_qs['resp_code'] != 0:
            return value_qs
        datas = value_qs['datas']
        print('datas', datas)
        # 校验datas的结构
        expected_keys = ['Warm_zone1', 'Warm_zone2', 'Warm_zone3', 'Warm_zone4', 'Warm_zone5',
                         'Warm_zone6', 'Warm_zone7', 'Warm_zone8', 'Warm_zone9', 'Warm_zone10',
                         'With_speed', 'N2_Con', 'UpHeaterPower', 'CoolerPower', 'LowHeaterPower', 'PassRate']

        if all(key in datas.get('A面', {}) and key in datas.get('B面', {}) for key in expected_keys):
            # 构建相对路径
            base_dir = os.path.dirname(os.path.abspath(__file__))
            relative_path = os.path.join(base_dir, '../Data/output', 'YH_reflow_result.csv')

            # 准备列名
            headers = ['side'] + expected_keys

            # 准备数据
            rows = []
            for side in ['A面', 'B面']:
                row = [side]
                for key in expected_keys:
                    row.append(datas[side][key][0])
                rows.append(row)

            # 将数据保存到CSV文件中，使用UTF-8编码
            with open(relative_path, mode='w', newline='', encoding='utf-8') as file:
                writer = csv.writer(file)
                writer.writerow(headers)  # 写入列名
                writer.writerows(rows)  # 写入数据行

        return generate_response(datas)
    except Exception as e:
        return generate_response(datas=datas, code=ResponseCode.ERROR, appendmessage='{0}'.format(str(e)))


def function_qs(Authorization, id):
    res = {}

    logger.info('------------------')
    logger.info('回流焊参数优化开始')
    logger.info('------------------')
    try:
        # model= joblib.load(path_model)
        y_pred = dataProcess(Authorization, id)
        logger.info('回流焊参数优化完成')
        # ......
        return generate_response(y_pred)
    except Exception as e:
        logger.error('回流焊参数优化失败，请检查文件名是否正确')
        res = generate_response(code=ResponseCode.WRONG_PARAM, appendmessage='{0}'.format(str(e)))
    return res


# i = "0.1"

def dataProcess(Authorization, id):
    print('开始')
    savePath = readConfig()
    # 运行预测模型并下载文件到本地
    prediction(Authorization, id, savePath)

    # 实例化问题对象
    problem = MyProblem1()
    algorithm = ea.moea_NSGA2_templet(
        problem,
        ea.Population(Encoding='BG', NIND=50),
        MAXGEN=500,  # 最大进化代数
        logTras=0)  # 表示每隔多少代记录一次日志信息，0表示不记录。
    algorithm.mutOper.Pm = 0.2  # 修改变异算子的变异概率
    algorithm.recOper.XOVR = 0.9  # 修改交叉算子的交叉概率
    # 求解
    res = ea.optimize(algorithm,
                      verbose=False,
                      drawing=0,
                      outputMsg=True,
                      drawLog=False,
                      saveFlag=False)
    print(res['Vars'])
    rs1 = process_optimization_results(res['Vars'], "./Data/output/reflow-a.dat", "A")

    problem = MyProblem2()
    algorithm = ea.moea_NSGA2_templet(
        problem,
        ea.Population(Encoding='BG', NIND=50),
        MAXGEN=500,  # 最大进化代数
        logTras=0)  # 表示每隔多少代记录一次日志信息，0表示不记录。
    algorithm.mutOper.Pm = 0.2  # 修改变异算子的变异概率
    algorithm.recOper.XOVR = 0.9  # 修改交叉算子的交叉概率
    # 求解
    res = ea.optimize(algorithm,
                      verbose=False,
                      drawing=0,
                      outputMsg=True,
                      drawLog=False,
                      saveFlag=False)
    print(res['Vars'])
    rs2 = process_optimization_results(res['Vars'], "./Data/output/reflow-b.dat", "B")

    ans = {"A面": rs1, "B面": rs2}
    return ans  # "回流焊参数优化成功"


def process_optimization_results(vars, model_path, side):
    if vars is not None:
        r = pd.DataFrame(vars)
        s = r
        s.columns = ['PCBThickness', 'PCBLength', 'PCBWidth',
                     'WarmZone1', 'WarmZone2', 'WarmZone3', 'WarmZone4',
                     'WarmZone5', 'WarmZone6', 'WarmZone7', 'WarmZone8',
                     'WarmZone9', 'WarmZone10', 'TapeSpeed', 'N2',
                     'UpHeaterPower', 'CoolerPower', 'LowHeaterPower']
        s = s.drop(columns=['PCBThickness', 'PCBLength', 'PCBWidth'])
        s.to_csv(f'./Data/output/result_{side.lower()}.csv', index=False)

        # 加载模型并预测
        model = pickle.load(open(model_path, "rb"))
        passrate = model.predict(vars.reshape(-1, 18))

        rs = {"Warm_zone1": [vars[0][3].astype('float')], "Warm_zone2": [vars[0][4].astype('float')],
              "Warm_zone3": [vars[0][5].astype('float')], "Warm_zone4": [vars[0][6].astype('float')],
              "Warm_zone5": [vars[0][7].astype('float')], "Warm_zone6": [vars[0][8].astype('float')],
              "Warm_zone7": [vars[0][9].astype('float')],
              "Warm_zone8": [vars[0][10].astype('float')], "Warm_zone9": [vars[0][11].astype('float')],
              "Warm_zone10": [vars[0][12].astype('float')], "With_speed": [vars[0][13].astype('float')],
              "N2_Con": [300], "UpHeaterPower": [90],
              "CoolerPower": [70], "LowHeaterPower": [90], "PassRate": [round(passrate[0], 3)]}
        # print(rs)
        data = pd.DataFrame(rs)
        data.to_csv(f'./Data/output/res-opt-{side.lower()}.csv', index=False)
    else:
        rs = {'message': f"{side}面未找到最优解，请重新运行"}
    return rs
# def dataProcess(Authorization, id):
#     print('开始')
#     savePath = readConfig()
#     # 运行预测模型并下载文件到本地
#     prediction(Authorization, id, savePath)
#     # 实例化问题对象
#     # global i
#     # i = "./Data/output/dtr.dat"
#
#     problem = MyProblem1()
#
#     # problem = MyProblem2()
#     # 构建算法
#     algorithm = ea.moea_NSGA2_templet(
#         problem,
#         ea.Population(Encoding='BG', NIND=50),
#         MAXGEN=500,  # 最大进化代数
#         logTras=0)  # 表示每隔多少代记录一次日志信息，0表示不记录。
#     algorithm.mutOper.Pm = 0.2  # 修改变异算子的变异概率
#     algorithm.recOper.XOVR = 0.9  # 修改交叉算子的交叉概率
#     # 求解
#     res = ea.optimize(algorithm,
#                       verbose=False,
#                       drawing=0,
#                       outputMsg=True,
#                       drawLog=False,
#                       saveFlag=False)
#     print(res['Vars'])
#     if res['Vars'] is not None:
#         r = pd.DataFrame(res['Vars'])
#         s_a = r
#         s_a.columns = ['PCBThickness', 'PCBLength', 'PCBWidth',
#                        'WarmZone1', 'WarmZone2', 'WarmZone3', 'WarmZone4',
#                        'WarmZone5', 'WarmZone6', 'WarmZone7', 'WarmZone8',
#                        'WarmZone9', 'WarmZone10', 'TapeSpeed', 'N2',
#                        'UpHeaterPower', 'CoolerPower', 'LowHeaterPower']
#         s_a = s_a.drop(columns=['PCBThickness', 'PCBLength', 'PCBWidth'])
#         s_a.to_csv('./Data/output/result1.csv', index=False)
#         # s = ['Warm_zone1','Warm_zone2','Warm_zone3','Warm_zone4','Warm_zone5','Warm_zone6','Warm_zone7',
#         #      'Warm_zone8','Warm_zone9','Warm_zone10','With_speed','N2_Con','UpJiaRePower','coolerPower','DownJiaRePower']
#         r = r.values
#         rs1 = {"Warm_zone1": [r[0][3].astype('float')], "Warm_zone2": [r[0][4].astype('float')],
#                "Warm_zone3": [r[0][5].astype('float')], "Warm_zone4": [r[0][6].astype('float')],
#                "Warm_zone5": [r[0][7].astype('float')], "Warm_zone6": [r[0][8].astype('float')],
#                "Warm_zone7": [r[0][9].astype('float')],
#                "Warm_zone8": [r[0][10].astype('float')], "Warm_zone9": [r[0][11].astype('float')],
#                "Warm_zone10": [r[0][12].astype('float')], "With_speed": [r[0][13].astype('float')],
#                "N2_Con": [300], "UpHeaterPower": [90],
#                "CoolerPower": [70], "LowHeaterPower": [90]}
#         print(rs1)
#         data = pd.DataFrame(rs1)
#         data.to_csv('./res-opt-a.csv', index=False)
#     else:
#         rs1 = {'message': "A面未找到最优解，请重新运行"}
#
#     problem = MyProblem2()
#     # 构建算法
#     algorithm = ea.moea_NSGA2_templet(
#         problem,
#         ea.Population(Encoding='BG', NIND=50),
#         MAXGEN=500,  # 最大进化代数
#         logTras=0)  # 表示每隔多少代记录一次日志信息，0表示不记录。
#     algorithm.mutOper.Pm = 0.2  # 修改变异算子的变异概率
#     algorithm.recOper.XOVR = 0.9  # 修改交叉算子的交叉概率
#     # 求解
#     res = ea.optimize(algorithm,
#                       verbose=False,
#                       drawing=0,
#                       outputMsg=True,
#                       drawLog=False,
#                       saveFlag=False)
#     print(res['Vars'])
#
#     if res['Vars'] is not None:
#         r = pd.DataFrame(res['Vars'])
#         s_b = r
#         s_b.columns = ['PCBThickness', 'PCBLength', 'PCBWidth',
#                        'WarmZone1', 'WarmZone2', 'WarmZone3', 'WarmZone4',
#                        'WarmZone5', 'WarmZone6', 'WarmZone7', 'WarmZone8',
#                        'WarmZone9', 'WarmZone10', 'TapeSpeed', 'N2',
#                        'UpHeaterPower', 'CoolerPower', 'LowHeaterPower']
#         s_b = s_b.drop(columns=['PCBThickness', 'PCBLength', 'PCBWidth'])
#         s_b.to_csv('./Data/output/result2.csv', index=False)
#         # s = ['Warm_zone1','Warm_zone2','Warm_zone3','Warm_zone4','Warm_zone5','Warm_zone6','Warm_zone7',
#         #      'Warm_zone8','Warm_zone9','Warm_zone10','With_speed','N2_Con','UpJiaRePower','coolerPower','DownJiaRePower']
#         r = r.values
#         rs2 = {"Warm_zone1": [r[0][3].astype('float')], "Warm_zone2": [r[0][4].astype('float')],
#                "Warm_zone3": [r[0][5].astype('float')], "Warm_zone4": [r[0][6].astype('float')],
#                "Warm_zone5": [r[0][7].astype('float')], "Warm_zone6": [r[0][8].astype('float')],
#                "Warm_zone7": [r[0][9].astype('float')],
#                "Warm_zone8": [r[0][10].astype('float')], "Warm_zone9": [r[0][11].astype('float')],
#                "Warm_zone10": [r[0][12].astype('float')], "With_speed": [r[0][13].astype('float')],
#                "N2_Con": [300], "UpHeaterPower": [90],
#                "CoolerPower": [70], "LowHeaterPower": [90]}
#         print(rs2)
#         data = pd.DataFrame(rs2)
#         # data.to_csv('./res-opt-b.csv', index=False)
#     else:
#         rs2 = {'message': "B面未找到最优解，请重新运行"}
#
#     ans = {}
#     ans = {"A面": rs1, "B面": rs2}
#     return ans  # "回流焊参数优化成功"


# A面为1，T也表示A面；B面为0
def encode_judge_res(value):
    if value in ['A', 'T']:
        return 1
    else:
        return 0


def prediction(Authorization, id, savePath):
    # 下载文件到本地
    fileName = id

    df = pd.read_csv(savePath + fileName)  # '.\\Data\\input\\回流焊数据集.csv'

    df['Board'] = df['Board'].apply(encode_judge_res)
    # df = df.drop(columns = ['PCB板长','PCB板宽','PCB板厚'])#,

    df = df.loc[df['PassRate'] != 0, :]
    df = df.reset_index(drop=True)

    # A面
    df1 = df.loc[df['Board'] == 1, :]
    df1 = df1.reset_index(drop=True)

    # B面
    df2 = df.loc[df['Board'] == 0, :]
    df2 = df2.reset_index(drop=True)

    # 删除板面
    df1 = df1.drop(columns=['Board'], axis=1)
    df2 = df2.drop(columns=['Board'], axis=1)

    # df1<2mm
    label1 = df1.pop('PassRate')
    # print(df1.info())
    forest = RandomForestRegressor(n_estimators=100,
                                   # criterion='mae',
                                   criterion='friedman_mse',
                                   random_state=1,
                                   n_jobs=-1)
    forest.fit(df1, label1)
    # importance = forest.feature_importances_ / np.max(forest.feature_importances_)
    # print(importance)
    # y_train_pred = forest.predict(df1)

    # plt.plot(label1)
    # plt.plot(y_train_pred)
    # plt.show()
    pickle.dump(forest, open("./Data/output/reflow-a.dat", "wb"))
    # print('df1:')
    # print('MSE train: %.5f' % (
    #     mean_squared_error(label1, y_train_pred)))
    # print('R^2 train: %.5f' % (
    #     r2_score(label1, y_train_pred)))

    # df2>2mm
    label2 = df2.pop('PassRate')
    # print(df2.info())
    forest = RandomForestRegressor(n_estimators=100,
                                   # criterion='mae',
                                   criterion='friedman_mse',
                                   random_state=1,
                                   n_jobs=-1)
    forest.fit(df2, label2)
    # importance = forest.feature_importances_ / np.max(forest.feature_importances_)
    # print(importance)
    y_train_pred = forest.predict(df2)

    # plt.plot(label2)
    # plt.plot(y_train_pred)
    # plt.show()
    pickle.dump(forest, open("./Data/output/reflow-b.dat", "wb"))
    # print('df2:')
    # print('MSE train: %.5f' % (
    #     mean_squared_error(label2, y_train_pred)))
    # print('R^2 train: %.5f' % (
    #     r2_score(label2, y_train_pred)))
    return "合格率预测成功"


# def download(Authorization, id, url, savePath):
#     """
#     将文件从minio下载下来
#     :param Authorization:
#     :param fileId:
#     :return:
#     """
#
#     headers = {
#         'Connection': 'keep-alive',
#         'Accept': 'application/json,tex/plain,*/*',
#         'X-Requested-with': 'XMLHttpRequest',
#         'Authorization': Authorization
#     }
#
#     Params = {
#         'id': id
#     }
#
#     datas = requests.get(url, headers=headers, params=Params)
#
#     savePath = savePath + id + ".csv"
#
#     with open(savePath, "wb") as code:
#         code.write(datas.content)
#
#     return id + ".csv"


def readConfig():
    """
    读取配置文件
    :return:
    """
    with open('./conf/application.yml', 'r', encoding='utf-8') as f:
        file_content = f.read()
        content = yaml.load(file_content, yaml.FullLoader)

        savePath = content["fileUploadDownload"]["download"]["savePath"]
        return savePath


class MyProblem1(ea.Problem):  # 继承Problem父类
    def __init__(self, M=1):
        name = 'MyProblem'  # 初始化name（函数名称，可以随意设置）
        Dim = 18  # 初始化Dim（决策变量维数）
        maxormins = [1] * M  # 初始化maxormins（目标最小最大化标记列表，1：最小化该目标；-1：最大化该目标）
        varTypes = [1] * Dim  # 初始化varTypes（决策变量的类型，0：实数；1：整数）
        # lb = [110,120,130,150,155,160,170,223,224,190,61,200,72,70,70]  # 决策变量下界
        # ub = [160,175,185,200,195,200,210,267,270,265,104,300,90,90,90]  # 决策变量上界
        # lb = [100,100,100,100,100,100,100,100,100,100,50,200,50,50,50]
        ub = [5, 500, 500, 200, 200, 200, 250, 250, 250, 250, 300, 300, 300, 150, 300, 100, 100, 100]
        lb = [0] * Dim  # 决策变量下界
        # ub = [300] * Dim  # 决策变量上界
        lbin = [1] * Dim  # 决策变量下边界（0表示不包含该变量的下边界，1表示包含）
        ubin = [1] * Dim  # 决策变量上边界（0表示不包含该变量的上边界，1表示包含）
        # 调用父类构造方法完成实例化
        ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin)

    def evalVars(self, Vars):  # 目标函数
        x1 = Vars[:, [3]]
        x2 = Vars[:, [4]]
        x3 = Vars[:, [5]]
        x4 = Vars[:, [6]]
        x5 = Vars[:, [7]]
        x6 = Vars[:, [8]]
        x7 = Vars[:, [9]]
        x8 = Vars[:, [10]]
        x9 = Vars[:, [11]]
        x10 = Vars[:, [12]]
        x11 = Vars[:, [13]]
        x12 = Vars[:, [14]]
        x13 = Vars[:, [15]]
        x14 = Vars[:, [16]]
        x15 = Vars[:, [17]]

        model = pickle.load(open("./Data/output/reflow-a.dat", "rb"))  # "dtr.dat"
        #  inputX = pd.DataFrame(Vars,columns=['温区一温度', '温区二温度', '温区三温度', '温区四温度', '温区五温度', '温区六温度', '温区七温度', '温区八温度',
        # '温区九温度', '温区十温度', '带速', '氧气浓度', '上加热器功率', '冷却器功率', '下加热器功率'])
        # X = [inputX for _ in range(len(model.input))]
        f1 = model.predict(Vars.reshape(-1, 18))
        # f1 = f1[:,np.newaxis]
        f2 = -x11
        # fl = 1/(1-f1.reshape(-1,1))
        f = 1 / (1 - f1.reshape(-1, 1))  # -x11/10
        # f = np.hstack([f1,f2])#
        # f = np.hstack([f2])
        print(f)
        CV = np.hstack(
            [110 - x1, x1 - x2 + 10, x2 - x3 + 10, x3 - 200, x3 - x4, x3 - x5, x3 - x6, x3 - x7, x4 - 220, x5 - 220,
             x6 - 220, x7 - 220, x7 - x8 + 30, x7 - x9 + 30, x7 - x10, x10 - x9, x9 - 280, x11 - 120])
        # CV = np.hstack([110-x1])
        return f, CV


class MyProblem2(ea.Problem):  # 继承Problem父类
    def __init__(self, M=1):
        name = 'MyProblem'  # 初始化name（函数名称，可以随意设置）
        Dim = 18  # 初始化Dim（决策变量维数）
        maxormins = [1] * M  # 初始化maxormins（目标最小最大化标记列表，1：最小化该目标；-1：最大化该目标）
        varTypes = [1] * Dim  # 初始化varTypes（决策变量的类型，0：实数；1：整数）
        # lb = [110,120,130,150,155,160,170,223,224,190,61,200,72,70,70]  # 决策变量下界
        # ub = [160,175,185,200,195,200,210,267,270,265,104,300,90,90,90]  # 决策变量上界
        # lb = [100,100,100,100,100,100,100,100,100,100,50,200,50,50,50]
        ub = [5, 500, 500, 200, 200, 200, 250, 250, 250, 250, 300, 300, 300, 150, 300, 100, 100, 100]
        lb = [0] * Dim  # 决策变量下界
        # ub = [300] * Dim  # 决策变量上界
        lbin = [1] * Dim  # 决策变量下边界（0表示不包含该变量的下边界，1表示包含）
        ubin = [1] * Dim  # 决策变量上边界（0表示不包含该变量的上边界，1表示包含）
        # 调用父类构造方法完成实例化
        ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin)

    def evalVars(self, Vars):  # 目标函数
        x1 = Vars[:, [3]]
        x2 = Vars[:, [4]]
        x3 = Vars[:, [5]]
        x4 = Vars[:, [6]]
        x5 = Vars[:, [7]]
        x6 = Vars[:, [8]]
        x7 = Vars[:, [9]]
        x8 = Vars[:, [10]]
        x9 = Vars[:, [11]]
        x10 = Vars[:, [12]]
        x11 = Vars[:, [13]]
        x12 = Vars[:, [14]]
        x13 = Vars[:, [15]]
        x14 = Vars[:, [16]]
        x15 = Vars[:, [17]]

        model = pickle.load(open("./Data/output/reflow-b.dat", "rb"))  # "dtr.dat"
        #  inputX = pd.DataFrame(Vars,columns=['温区一温度', '温区二温度', '温区三温度', '温区四温度', '温区五温度', '温区六温度', '温区七温度', '温区八温度',
        # '温区九温度', '温区十温度', '带速', '氧气浓度', '上加热器功率', '冷却器功率', '下加热器功率'])
        # X = [inputX for _ in range(len(model.input))]
        f1 = model.predict(Vars.reshape(-1, 18))
        # f1 = f1[:,np.newaxis]
        f2 = -x11
        # fl = 1/(1-f1.reshape(-1,1))
        f = 1 / (1 - f1.reshape(-1, 1))  # -x11/10
        # f = np.hstack([f1,f2])#
        # f = np.hstack([f2])
        print(f)
        CV = np.hstack(
            [110 - x1, x1 - x2 + 10, x2 - x3 + 10, x3 - 200, x3 - x4, x3 - x5, x3 - x6, x3 - x7, x4 - 220, x5 - 220,
             x6 - 220, x7 - 220, x7 - x8 + 30, x7 - x9 + 30, x7 - x10, x10 - x9, x9 - 280, x11 - 120])
        # CV = np.hstack([110-x1])
        return f, CV
